/* Ty, a programming language interpreter
 * Copyright (C) 2007 Nick Thomas
 *
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef TY_IMAGE_H
#define TY_IMAGE_H

#include "CuTest.h"
#include "data.h"
#include "data_stack.h"

/* This file deals with Ty images, as well as the heap and memory management,
 * since the two are fairly intertwined issues. An image consists of a data
 * stack, a call stack, a dictionary, and a heap. The contents of the data
 * stack, the call stack, and dictionary act as the root set for the garbage
 * collection of the heap.
 *
 * XXX: Right now, only the data stack and heap are implemented.
 *
 * At the moment, our heap uses simple single-generation copying garbage
 * collection. This can be improved if necessary.
 *
 * One difficulty for the garbage collector is that chunks are two words, and
 * every single bit of these two words is already in use, which means that some
 * auxiliary storage is necessary to hold the one bit per chunk we need to
 * indicate whether the chunk is copied or not. In order to hold this data, we
 * allocate an array of characters in parallel to the heap, with each character
 * holding the copy bit for the chunk at the corresponding index in the heap.
 */

/* XXX: These numbers will need tuning. */
#define TY_HEAP_INITIAL_SIZE 16384
#define TY_HEAP_RESIZE_THRESHOLD_NUMERATOR 3
#define TY_HEAP_RESIZE_THRESHOLD_DENOMINATOR 4

typedef struct {
    uintptr_t size;
    /* The "end" of the heap is the index in the heap where chunks are to
     * be allocated from.
     */
    uintptr_t end;
    ty_chunk *heap;
    ty_chunk *other_heap;
    char *mark_array;
} ty_heap;

typedef struct {
    ty_data_stack data_stack;
    ty_heap heap;
} ty_image;

/* Initializes the given image. */
void ty_make_image(ty_image *image);

/* Initializes the given heap with the given initial size (in chunks). */
void ty_make_heap(ty_heap *heap, uintptr_t size);

/* Allocates a new chunk in the given image, returning a chunk pointer
 * suitable for input to ty_make_obj().
 */
ty_chunk *ty_new_chunk(ty_image *image);

/* Forces a garbage collection of the given image. Resizes the heap if it's
 * a little full.
 */
void ty_do_garbage_collection(ty_image *image);

/* Resizes the heap of the given image. */
void ty_resize_heap(ty_image *image, uintptr_t size);

/* Unit tests. */
void ty_test_image(CuTest *tc);

#endif
